package com.bbva.kyfb.kyfbdaofiimpl.pau;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;

import com.bbva.jee.arq.spring.core.contexto.ArqSpringContext;
import com.bbva.jee.arq.spring.core.gce.ExcepcionEjecucionAplicacion;
import com.bbva.jee.arq.spring.core.log.I18nLog;
import com.bbva.jee.arq.spring.core.log.I18nLogFactory;
import com.bbva.jee.arq.spring.core.util.excepciones.PropiedadNoEncontradaExcepcion;
import com.bbva.kyfb.kyfbdaofi.IValidadorPAU;
import com.bbva.kyfb.kyfbdto.firmas.bo.UsuarioInfo;
import com.bbva.kyfb.kyfbdto.firmas.errores.Errores_kyfb_servicios;
import com.bbva.kyfb.kyfbutils.constantes.UtilFO;
import com.bbva.kyfb.kyfbutils.errores.ValidationUtils;
import com.bbva.kyfb.kyfbutils.invoker.InvokerUtils;
import com.bbva.kyfb.kyfbutils.pau.ConstantesPAU;
import com.bbva.kygu.clientcontractws.beans.RespuestaTokenType;
import com.bbva.kygu.clientcontractws.beans.RespuestaUsuarioUniqType;
import com.bbva.kygu.clientcontractws.beans.UsuarioType;
import com.bbva.kytv.interfaces.kygu.IGestionTokenUsuario;
import com.bbva.kytv.interfaces.kygu.IModificacionDatosBasicos;
import com.bbva.kytv.util.exception.KYTVException;
import com.grupobbva.sl.an.pau.cliente.PAUSesion;
import com.grupobbva.sl.an.pau.comun.Constantes;

/**
 * The Class ValidadorPAUImpl.
 */
@Component(value = "validadorPAU")
public class ValidadorPAUImpl implements IValidadorPAU {
	/** Variable LOG. */
	private static final I18nLog LOG = I18nLogFactory
			.getLogI18n(ValidadorPAUImpl.class);

	/** The Constant TOKEN_BLOQUEADO. */
	private static final int TOKEN_BLOQUEADO = 6;
	/** The Constant TOKEN_ACTIVO. */
	private static final int TOKEN_ACTIVO = 1;

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String comprobarFormulaOTP(final String token,
			final String claveToken, final String resultadoFormula,
			final String numeroAleatorio, final UsuarioInfo usuario) {
		final Object[] obligatorios = new Object[] { token, claveToken,
				resultadoFormula, numeroAleatorio, usuario };
		ValidationUtils.validarObligatorios(obligatorios,
				Errores_kyfb_servicios.CREDENCIALES_INCORRECTAS, true);
		if (numeroAleatorio.length() < ConstantesPAU.LONGITUD_MIN_NUMALEAT || 
				numeroAleatorio.length() > ConstantesPAU.LONGITUD_MAX_NUMALEAT){
			  throw new ExcepcionEjecucionAplicacion(Errores_kyfb_servicios.CREDENCIALES_INCORRECTAS);
		}
		final AutenticadorPAU pau = new AutenticadorPAU(ConstantesPAU.APLICACION,
				ConstantesPAU.CANAL, ConstantesPAU.OPERACION,
				ConstantesPAU.SECUENCIA_FORMULA_VASCO,
				usuario.getUsuarioConReferencia());

		final String resultadoPAU = pau.comprobarFormulaOTP(token, claveToken,
				resultadoFormula, numeroAleatorio);
		gestionarResultadoIncorrecto(resultadoPAU,
				ConstantesPAU.SECUENCIA_FORMULA_VASCO);
		return ConstantesPAU.AUT_OK;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String validaClaveOperaciones(final UsuarioInfo usuario,
			final String claveOperaciones) {
		final Object[] obligatorios = new Object[] { usuario, claveOperaciones };
		ValidationUtils.validarObligatorios(obligatorios,
				Errores_kyfb_servicios.CREDENCIALES_INCORRECTAS, true);

		final AutenticadorPAU pau = new AutenticadorPAU(ConstantesPAU.APLICACION,
				ConstantesPAU.CANAL, ConstantesPAU.OPERACION,
				ConstantesPAU.SECUENCIA_CLAVEOP,
				usuario.getUsuarioConReferencia());

		final String resultadoPAU = pau.validaClaveOperaciones(
				usuario.getUsuarioConReferencia(), claveOperaciones);
		gestionarResultadoIncorrecto(resultadoPAU,
				ConstantesPAU.SECUENCIA_CLAVEOP);
		return ConstantesPAU.AUT_OK;
	}

	/**
	 * Valida clopvac.
	 * 
	 * @param token
	 *            the token
	 * @param claveToken
	 *            the clave token
	 * @param usuario
	 *            the usuario
	 * @param claveOperaciones
	 *            the clave operaciones
	 * @param aplicacion
	 *            the aplicacion
	 * @return the string
	 */
	private String validaCLOPVAC(final String token, final String claveToken,
			final UsuarioInfo usuario, final String claveOperaciones,
			final String aplicacion) {
		final Object[] obligatorios = new Object[] { token, claveToken, usuario,
				claveOperaciones };
		ValidationUtils.validarObligatorios(obligatorios,
				Errores_kyfb_servicios.CREDENCIALES_INCORRECTAS, true);
		final AutenticadorPAU pau = new AutenticadorPAU(aplicacion,
				ConstantesPAU.CANAL, ConstantesPAU.OPERACION,
				ConstantesPAU.SECUENCIA_CLAVEOP_VASCO,
				usuario.getUsuarioConReferencia());

		final String resultadoPAU = pau
				.validaClaveOperacionesVasco(token, claveToken,
						usuario.getUsuarioConReferencia(), claveOperaciones);
		gestionarResultadoIncorrecto(resultadoPAU,
				ConstantesPAU.SECUENCIA_CLAVEOP_VASCO);
		return ConstantesPAU.AUT_OK;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String validaClaveOperacionesVasco(final String token,
			final String claveToken, final UsuarioInfo usuario,
			final String claveOperaciones) {
		return validaCLOPVAC(token, claveToken, usuario, claveOperaciones,
				ConstantesPAU.APLICACION);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String validaClaveOperacionesVascoCMP(final String token,
			final String claveToken, final UsuarioInfo usuario,
			final String claveOperaciones) {
		return validaCLOPVAC(token, claveToken, usuario, claveOperaciones,
				ConstantesPAU.APLICACION_CMP);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String validaFORMULA(final UsuarioInfo usuario,
			final String resultadoFormula, final String numeroAleatorio) {
		final Object[] obligatorios = new Object[] { usuario, resultadoFormula,
				numeroAleatorio };
		ValidationUtils.validarObligatorios(obligatorios,
				Errores_kyfb_servicios.CREDENCIALES_INCORRECTAS, true);
		if (numeroAleatorio.length() < ConstantesPAU.LONGITUD_MIN_NUMALEAT || 
				numeroAleatorio.length() > ConstantesPAU.LONGITUD_MAX_NUMALEAT){
			  throw new ExcepcionEjecucionAplicacion(Errores_kyfb_servicios.CREDENCIALES_INCORRECTAS);
		}
		final AutenticadorPAU pau = new AutenticadorPAU(ConstantesPAU.APLICACION,
				ConstantesPAU.CANAL, ConstantesPAU.OPERACION,
				ConstantesPAU.SECUENCIA_FORMULA,
				usuario.getUsuarioConReferencia());

		final String resultadoPAU = pau.validaFORMULA(
				usuario.getUsuarioConReferencia(), resultadoFormula,
				numeroAleatorio);
		gestionarResultadoIncorrecto(resultadoPAU,
				ConstantesPAU.SECUENCIA_FORMULA);
		return ConstantesPAU.AUT_OK;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String enviaFORMULAOTP(final String telefono, final String mensaje,
			final UsuarioInfo usuario) throws PropiedadNoEncontradaExcepcion {
		final Object[] obligatorios = new Object[] { telefono, usuario };
		ValidationUtils.validarObligatorios(obligatorios,
				Errores_kyfb_servicios.CREDENCIALES_INCORRECTAS, true);
		final AutenticadorPAU pau = new AutenticadorPAU(ConstantesPAU.APLICACION,
				ConstantesPAU.CANAL, ConstantesPAU.OPERACION,
				ConstantesPAU.SECUENCIA_FORMULA_OTP,
				usuario.getUsuarioConReferencia());

		final PAUSesion sesion = pau.enviaSesionOTP(telefono, mensaje);
		/* Guardaremos la sesion en base de datos */
		final String resultadoPAU = sesion.getEstado();
		gestionarResultadoIncorrecto(resultadoPAU,
				ConstantesPAU.SECUENCIA_FORMULA_OTP);

		// TODO el usuario auditor
		// devolvemos el id de la sesion guardada
		return pau.guardarSesion(usuario, sesion,
				ArqSpringContext.getPropiedad(UtilFO.USUARIO_BBDD_TLSB));
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String enviaCLOPSMS(final String telefono, final String mensaje,
			final UsuarioInfo usuario) throws PropiedadNoEncontradaExcepcion {
		final Object[] obligatorios = new Object[] { telefono, usuario };
		ValidationUtils.validarObligatorios(obligatorios,
				Errores_kyfb_servicios.CREDENCIALES_INCORRECTAS, true);

		final AutenticadorPAU pau = new AutenticadorPAU(ConstantesPAU.APLICACION,
				ConstantesPAU.CANAL, ConstantesPAU.OPERACION,
				ConstantesPAU.SECUENCIA_CLAVEOP_OTP,
				usuario.getUsuarioConReferencia());
		final PAUSesion sesion = pau.enviaSesionOTP(telefono, mensaje);
		/* Guardaremos la sesion en base de datos */
		final String resultadoPAU = sesion.getEstado();
		gestionarResultadoIncorrecto(resultadoPAU,
				ConstantesPAU.SECUENCIA_CLAVEOP_OTP);
		return pau.guardarSesion(usuario, sesion,
				ArqSpringContext.getPropiedad(UtilFO.USUARIO_BBDD_TLSB));
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String validaFORMULAOTP(final UsuarioInfo usuario,
			final String idSesion, final String codigoSMS,
			final String resultadoFormula, final String numeroAleatorio) {
		final Object[] obligatorios = new Object[] { usuario, idSesion, codigoSMS,
				resultadoFormula, numeroAleatorio };
		ValidationUtils.validarObligatorios(obligatorios,
				Errores_kyfb_servicios.CREDENCIALES_INCORRECTAS, true);
		if (numeroAleatorio.length() < ConstantesPAU.LONGITUD_MIN_NUMALEAT || 
				numeroAleatorio.length() > ConstantesPAU.LONGITUD_MAX_NUMALEAT){
			  throw new ExcepcionEjecucionAplicacion(Errores_kyfb_servicios.CREDENCIALES_INCORRECTAS);
		}
		final AutenticadorPAU pau = new AutenticadorPAU();
		/* Se obtiene la sesion de base de datos */
		// TODO
		final PAUSesion sesion = pau.devuelveSesion(usuario, idSesion);
		final String resultadoPAU = pau.validaFORMULAOTP(sesion, codigoSMS,
				resultadoFormula, numeroAleatorio);
		gestionarResultadoIncorrecto(resultadoPAU, sesion.getSec());
		return ConstantesPAU.AUT_OK;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String validaCLOPSMS(final String idSesion, final String codigoSMS,
			final UsuarioInfo usuario, final String claveOperaciones) {
		final Object[] obligatorios = new Object[] { idSesion, codigoSMS, usuario,
				claveOperaciones };
		ValidationUtils.validarObligatorios(obligatorios,
				Errores_kyfb_servicios.CREDENCIALES_INCORRECTAS, true);

		final AutenticadorPAU pau = new AutenticadorPAU();
		/* Se obtiene la sesion de base de datos */
		// TODO
		final PAUSesion sesion = pau.devuelveSesion(usuario, idSesion);

		final String resultadoPAU = pau.validaCLOPSMS(sesion, codigoSMS,
				usuario.getUsuarioConReferencia(), claveOperaciones);
		gestionarResultadoIncorrecto(resultadoPAU, sesion.getSec());
		return ConstantesPAU.AUT_OK;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public List<String> validacionesToken(final String referencia,
			final String canal, final int bancoInterno,
			final int bancoProducto, final int producto, final int subproducto,
			final String codUsuario) throws ExcepcionEjecucionAplicacion {

		final List<String> lResult = new ArrayList<String>(5);

		// Llamada ws ConsultaDatosBasicos
		LOG.info("ValidadorPauImpl --- validacionesToken (parametros), canal: "
				+ canal + ",bancoInterno: " + bancoInterno + ",referencia: "
				+ referencia + ",bancoProducto: " + bancoProducto
				+ ",producto: " + producto + ",subproducto: " + subproducto
				+ ",codUsuario: " + codUsuario + ",idioma:");
		RespuestaUsuarioUniqType respuesta = null;
		UsuarioType usuario = null;
		try {
			respuesta = ((IModificacionDatosBasicos) InvokerUtils
					.getBeanInvoker(com.bbva.kyfb.kyfbutils.constantes.ConstantesFO.VAR_MODIF_DATOS_BASICOS,
							IModificacionDatosBasicos.class))
							.consultarDatosBasicosUsuario(canal, bancoInterno,
									referencia, bancoProducto, producto, subproducto,
									codUsuario, "");
			usuario = respuesta.getUsuario();
		} catch (final KYTVException e) {
			throw new ExcepcionEjecucionAplicacion(
					Errores_kyfb_servicios.SERVICIO_NO_DISPONIBLE, e);
		}

		addInfoValidacionToken(lResult, respuesta, usuario);

		if (respuesta.getRespuesta().getCodRetorno()
				.equals(ConstantesPAU.CODRETORNO_WS)) {
			throw new ExcepcionEjecucionAplicacion(
					Errores_kyfb_servicios.EL_USUARIO_NO_EXISTE);
		}

		final String nuSerieToken = usuario.getDispSeguridad().trim();
		if (StringUtils.isBlank(nuSerieToken)) {
			if (empresaTieneAsociadoToken(canal, bancoInterno, referencia,
					bancoProducto, producto, subproducto, 0)) {
				throw new ExcepcionEjecucionAplicacion(
						Errores_kyfb_servicios.USUARIO_SIN_TOKEN);
			}
			throw new ExcepcionEjecucionAplicacion(
					Errores_kyfb_servicios.EMPRESA_SIN_TOKEN);
		}

		comprobarEstadoToken(usuario.getEstadoToken());

		// Lanzamos algunos de los datos obtenidos del ws ConsultaDatosBasicos
		return lResult;
	}

	/**
	 * Adds the info validacion token.
	 * 
	 * @param lResult
	 *            the v result
	 * @param resp
	 *            the resp
	 * @param usuario
	 *            the usuario
	 */
	private void addInfoValidacionToken(final List<String> lResult,
			final RespuestaUsuarioUniqType resp, final UsuarioType usuario) {
		if (resp.getRespuesta().getCodError().equals("0")) {
			String esUsuarioCMP;
			String codigoUsuario;
			if (usuario.getEsUsuarioCMP() != null
					&& usuario.getEsUsuarioCMP().equals("S")) {
				esUsuarioCMP = "S";
			} else {
				esUsuarioCMP = "N";
			}
			if (!StringUtils.isBlank(usuario.getIdGlobal())) {
				codigoUsuario = usuario.getIdGlobal().trim();
			} else if (!StringUtils.isBlank(usuario.getCodUsuario())) {
				codigoUsuario = usuario.getCodUsuario().trim();
			} else {
				codigoUsuario = "";
			}
			// Añadimos al vector de respuesta los campos de informacion del
			// usuario
			// Numero del Dispositivo de seguridad, Estado del Token, CMP(S-N),
			// Codigo del usuario
			lResult.add(usuario.getDispSeguridad().trim());
			lResult.add(usuario.getEstadoToken().trim());
			lResult.add(esUsuarioCMP);
			lResult.add(codigoUsuario);
		}
	}

	/**
	 * Comprobar estado token.
	 * 
	 * @param estadoToken
	 *            the estado token
	 */
	private void comprobarEstadoToken(final String estadoToken) {
		if (!estadoToken.trim().equals("")) {
			final int estadoTknNum = Integer.parseInt(estadoToken.trim());
			if (estadoTknNum == TOKEN_BLOQUEADO) {
				throw new ExcepcionEjecucionAplicacion(
						Errores_kyfb_servicios.DISPOSITIVO_BLOQUEADO);
			}

			if (estadoTknNum != TOKEN_ACTIVO) {
				throw new ExcepcionEjecucionAplicacion(
						Errores_kyfb_servicios.TOKEN_INACTIVO_PARA_EL_USUARIO);
			}
		}
	}

	/**
	 * Devuelve si la empresa tiene asociado un token.
	 * 
	 * @param canal
	 *            the canal
	 * @param bancoInterno
	 *            the banco interno
	 * @param referencia
	 *            the referencia
	 * @param bancoProducto
	 *            the banco producto
	 * @param producto
	 *            the producto
	 * @param subproducto
	 *            the subproducto
	 * @param iCodServicio
	 *            the i cod servicio
	 * @return true, if successful
	 */
	private boolean empresaTieneAsociadoToken(final String canal,
			final int bancoInterno, final String referencia,
			final int bancoProducto, final int producto, final int subproducto,
			final int iCodServicio) {
		RespuestaTokenType resp = null;

		try {
			final IGestionTokenUsuario infoToken = (IGestionTokenUsuario) InvokerUtils.getBeanInvoker(
					com.bbva.kyfb.kyfbutils.constantes.ConstantesFO.VAR_TOKEN_USUARIO_INVOKER,
					IGestionTokenUsuario.class);
			resp = infoToken.listarTodosTokens(
					canal, bancoInterno, referencia, bancoProducto, producto,
					subproducto);
		} catch (final KYTVException e) {
			throw new ExcepcionEjecucionAplicacion(
					Errores_kyfb_servicios.SERVICIO_NO_DISPONIBLE, e);
		}


		boolean hasToken = false;
		if (resp != null && resp.getRespuesta().getCodError().equals("0")
				&& !resp.getListaToken().getToken().isEmpty()) {
			hasToken = true;
		}
		return hasToken;
	}

	/**
	 * Gestionar resultado incorrecto.
	 * 
	 * @param resultadoPAU
	 *            the resultado pau
	 * @param secuencia
	 *            the secuencia
	 */
	private void gestionarResultadoIncorrecto(final String resultadoPAU,
			final String secuencia) {
		if (!resultadoPAU.equalsIgnoreCase(Constantes.AUT_OK)
				&& !resultadoPAU.equalsIgnoreCase(Constantes.AUT_SIG)) {
			final String errorPAU = resultadoPAU + secuencia;
			throw new ExcepcionEjecucionAplicacion(
					ConstantesPAU.erroresPAUMap.get(errorPAU));
		}
	}
}
